package nl.boelen.game.server.entity;

import java.util.ArrayList;
import java.util.List;

import nl.boelen.game.net.packet.Packet;
import nl.boelen.game.net.packet.Packet10Join;
import nl.boelen.game.net.packet.Packet11Leave;
import nl.boelen.game.net.packet.Packet14CheckConnection;
import nl.boelen.game.options.Option;
import nl.boelen.game.server.Server;
import nl.boelen.game.server.connection.ServerTCPSender;
import nl.boelen.game.server.connection.ServerUDP;

public class Players {
    private static final List<PlayerMP> connectedPlayers = new ArrayList<PlayerMP>();
    private Server server;
    private ServerUDP UDP;
    private ServerTCPSender TCP;

    public Players(Server server) {
        this.server = server;
    }

    public void setConnections(ServerUDP UDP, ServerTCPSender TCP) {
        this.UDP = UDP;
        this.TCP = TCP;
    }

    public void addPlayerMP(PlayerMP player, Packet10Join packet) {
        boolean alreadyConnected = false;

        for (PlayerMP p : getConnectedPlayers()) {
            if (player.getUniqueKey().equals(p.getUniqueKey())) {
                if (p.getIp() == null) {
                    p.setIp(player.getIp());
                }
                if (p.getTCPPort() == -1) {
                    p.setTCPPort(player.getTCPPort());
                }
                alreadyConnected = true;
            } else {
                TCP.sendPacket(packet, p.getIp(), p.getTCPPort());

                Packet10Join sendpacket = new Packet10Join(p.getUserName(), p.getUniqueKey(), p.getShirtColor(), p.getX(), p.getY(),
                        p.getTCPPort(), p.getUDPPort(), p.getMovingDirection(), p.getMaxhp(), p.getHp());

                TCP.sendPacket(sendpacket, player.getIp(), player.getTCPPort());
            }
        }
        if (!alreadyConnected) {
            getConnectedPlayers().add(player);
        }
        server.serverGUI.updateTable();
    }

    public void removePlayerMP(Packet11Leave packet) {
        int index = 0;
        for (PlayerMP p : getConnectedPlayers()) {
            if (p.getUniqueKey().equals(packet.getUniqueKey())) {
                getConnectedPlayers().remove(index);
                break;
            }
            index++;
        }
        sendTCPDataToAllClients(packet);
        server.serverGUI.updateTable();
    }

    public void removePlayerMP(PlayerMP player) {
        int index = 0;
        for (PlayerMP p : getConnectedPlayers()) {
            if (p.getUniqueKey().equals(player.getUniqueKey())) {
                getConnectedPlayers().remove(index);
                break;
            }
            index++;
        }
        sendTCPDataToAllClients(new Packet11Leave(player.getUserName(), player.getUniqueKey()));
        server.serverGUI.updateTable();
    }

    public void sendUDPDataToAllClients(Packet packet) {
        for (PlayerMP p : getConnectedPlayers()) {
            UDP.sendPacket(packet, p.getIp(), p.getUDPPort());
        }
    }

    public void sendTCPDataToAllClients(Packet packet) {
        for (PlayerMP p : getConnectedPlayers()) {
            TCP.sendPacket(packet, p.getIp(), p.getTCPPort());
        }
    }

    public void sendUDPDataToAllClientsExcept(PlayerMP player, Packet packet) {
        for (PlayerMP p : getConnectedPlayers()) {
            if (p != player) {
                UDP.sendPacket(packet, p.getIp(), p.getUDPPort());
            }
        }
    }

    public void sendTCPDataToAllClientsExcept(PlayerMP player, Packet packet) {
        for (PlayerMP p : getConnectedPlayers()) {
            if (p != player) {
                TCP.sendPacket(packet, p.getIp(), p.getTCPPort());
            }
        }
    }

    public void tick() {
        PlayerMP remove = null;
        long currentTime = System.currentTimeMillis();
        for (PlayerMP p : getConnectedPlayers()) {
            if (currentTime > (p.getLastChecked() + Option.millisecBeforeCheckingConnection)) {
                if (!p.isChecking()) {
                    // Its a long time since we heard something from the
                    // player, is it still connected?
                    p.checking();
                    Packet14CheckConnection packet = new Packet14CheckConnection(p.getUniqueKey());
                    TCP.sendPacket(p, packet);
                    p.hasChecked();
                } else {
                    // We didn't received any response in the previous
                    // check, so we assume the player is disconnected
                    remove = p;
                }
            }
        }

        if (remove != null) {
            removePlayerMP(remove);
        }
    }

    public PlayerMP getPlayerMP(String uniqueKey) {
        for (PlayerMP p : getConnectedPlayers()) {
            if (p.getUniqueKey().equals(uniqueKey)) {
                return p;
            }
        }
        return null;
    }

    public PlayerMP getPlayerMP(int index) {
        if (index < getConnectedPlayers().size() && getConnectedPlayers().get(index) != null) {
            return getConnectedPlayers().get(index);
        }
        return null;
    }

    public synchronized List<PlayerMP> getConnectedPlayers() {
        return connectedPlayers;
    }
}
